﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading;
using System.Windows.Threading;

namespace SocketServer
{
    /// <summary>
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : Window
    {
        MongoService dbs = new MongoService();
        private NotifyIconWrapper notify;
        private TcpListener listener;
        private bool isListener = true;
        private Dictionary<string, Socket> clients = new Dictionary<string, Socket>();
        public MainWindow()
        {
            InitializeComponent();
            notify = new NotifyIconWrapper();
        }


        /// <summary>
        /// 窗口关闭
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            e.Cancel = true;
            this.Hide();
            this.ShowInTaskbar = true;
        }

        /// <summary>
        /// 开始监控客户端
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnstart_Click(object sender, RoutedEventArgs e)
        {
            isListener = true;
            Log("正在启动监听……");
            var ip = IPAddress.Parse("10.0.5.100");
            listener = new TcpListener(ip, 23456);
            listener.Start();
            ThreadPool.QueueUserWorkItem(StartHost);
            ThreadPool.QueueUserWorkItem(ClientNum);
        }

        /// <summary>
        /// 定时刷新客户端状态
        /// </summary>
        /// <param name="o"></param>
        private void ClientNum(object o)
        {
            while (true)
            {
                TimeToClear();
                Dispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate
                {
                    tbclientnum.Text = "当前客户端数：" + dbs.GetClientCount();
                });
                Thread.Sleep(10000);
            }
        }

        /// <summary>
        /// 主机监控
        /// </summary>
        /// <param name="c"></param>
        private void StartHost(object c)
        {
            while (isListener)
            {
                try
                {
                    var client = listener.AcceptSocket();
                    ThreadPool.QueueUserWorkItem(StartClient, client);
                }
                catch (Exception ex)
                {
                    Log("正常抛出："+ex.Message);
                }
            }
        }

        private void Log(string msg)
        {
            Dispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate {
                if (lbxmsg.Items.Count > 1000)
                {
                    lbxmsg.Items.Clear();
                }
                lbxmsg.Items.Insert(0, msg);
                lbxmsg.Items.Refresh();
            });
        }

        /// <summary>
        /// 客户端套接字
        /// </summary>
        /// <param name="c"></param>
        private void StartClient(object c)
        {
            bool iskill = false;
            var socket = (Socket)c;
            while (!iskill)
            {
                try
                {
                    int bytei = 0;
                    var data = new byte[1024];
                    bytei = socket.Receive(data);
                    string req = Encoding.UTF8.GetString(data);
                    req = req.Substring(0, req.IndexOf("\0"));
                    if (string.IsNullOrEmpty(req))
                    {
                        continue;
                    }
                    if (req.IndexOf("<policy-file-request/>") >= 0)//flash需要2次授权
                    {
                        var xml = "<cross-domain-policy> "
        + "<allow-access-from domain=\"*\" to-ports=\"1025-23456\"/>"
     + "</cross-domain-policy> ";
                        socket.Send(Encoding.UTF8.GetBytes(xml + "\0"));
                        socket.Close();
                        iskill = true;
                        break;
                    }
                    DoCommend(socket,req);
                }
                catch (Exception)
                {
                    iskill = true;
                    if (socket != null)
                    {
                        try
                        {
                            var ipaddress = (socket.RemoteEndPoint as IPEndPoint).Address.ToString();
                            var port = (socket.RemoteEndPoint as IPEndPoint).Port;
                            var cbean = dbs.Get(ipaddress, port);
                            if (cbean != null)
                            {
                                dbs.LoginOut(cbean.Cid);
                                clients.Remove(cbean.Cid);
                                Log("客户端" + cbean.Name + "断开链接！");
                            }
                        }
                        catch (Exception)
                        {
                        }
                    }
                    break;
                }
            }
        }

        /// <summary>
        /// 接收命令
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="cmdstr"></param>
        private void DoCommend(Socket socket, string cmdstr)//msg$tankcart01$control01$Hello Word!!!!!!!!!!!
        {
            string[] cmd = cmdstr.Split('$');
            switch (cmd[0])
            {
                case "cmd":
                    DoCmd(socket,cmd[1],cmd[2]);
                    break;
                case "msg":
                    DoMessage(socket, cmd[1],cmd[2],cmd[3]);
                    break;
                case"move":
                    Move(socket,cmd[2]);
                    break;
                default:
                    break;
            }
            Log(cmdstr);
        }

        /// <summary>
        /// 执行命令
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="name"></param>
        /// <param name="valstr"></param>
        private void DoCmd(Socket socket,string name,string valstr)
        {
            SocketBean beanin = dbs.GetByName(name);
            string[] val = valstr.Split('|');
            switch (val[0])
            {
                case "in":
                    if (beanin == null)
                    {
                        beanin = new SocketBean(socket, name);
                        dbs.Add(beanin);
                    }
                    else
                    {
                        beanin.Ipaddress = (socket.RemoteEndPoint as IPEndPoint).Address.ToString();
                        beanin.Port = (socket.RemoteEndPoint as IPEndPoint).Port;
                        beanin.IsOnline = true;
                        dbs.Update(beanin);
                    }
                    clients.Add(beanin.Cid, socket);
                    Log("一个客户端:" + beanin.Name + "接入！");
                    break;
                case "out":
                    dbs.LoginOut(beanin.Cid);
                    clients.Remove(beanin.Cid);
                    Log("一个客户端:" + name + "登出！");
                    socket.Close();
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="name"></param>
        /// <param name="msgstr"></param>
        private void DoMessage(Socket socket,string from,string to, string msgstr)//to|msg|
        {
            if (to == "all")
            {
                SendToAll(from, msgstr);
            }
            else {
                var cbean = dbs.GetByName(to);
                if (cbean != null)
                {
                    if (clients.ContainsKey(cbean.Cid))
                    {
                        var client = clients[cbean.Cid];
                        SendToClient(client, from, msgstr);
                    }
                }
            }
        }

        /// <summary>
        /// 控制移动
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="cmdstr"></param>
        private void Move(Socket socket, string cmdstr)//to|0,255,0,255
        {
            
            string[] val = cmdstr.Split('|');
            SocketBean beanin = dbs.GetByName(val[0]);
            if (!clients.ContainsKey(beanin.Cid)) return;
            var toclient = clients[beanin.Cid];
            SocketAsyncEventArgs sendarync = new SocketAsyncEventArgs();
            byte[] buffer = Encoding.UTF8.GetBytes(string.Format("$move&{0}$", val[1]).Replace(',','|'));
            sendarync.SetBuffer(buffer, 0, buffer.Length);
            toclient.SendAsync(sendarync);
        }

        /// <summary>
        /// 广播
        /// </summary>
        /// <param name="uid"></param>
        /// <param name="msg"></param>
        private void SendToAll(string from,string msg)
        {
            var ss = clients.Values.ToArray();
            foreach (var item in ss)
            {
                try
                {
                    item.Send(Encoding.UTF8.GetBytes(string.Format("msg${0}${1}", from, msg)));
                }
                catch (Exception e)
                {
                    Log(e.Message);
                }
            }
        }

        /// <summary>
        /// 对单个客户端发消息
        /// </summary>
        /// <param name="socket"></param>
        /// <param name="msg"></param>
        private void SendToClient(Socket socket,string form, string msg)
        {
            try
            {
                SocketAsyncEventArgs sendarync = new SocketAsyncEventArgs();
                byte[] buffer = Encoding.UTF8.GetBytes(string.Format("msg${0}${1}", form, msg));//msg$tankcart01$radal|1|200
                sendarync.SetBuffer(buffer, 0, buffer.Length);
                socket.SendAsync(sendarync);
                //socket.Send(Encoding.UTF8.GetBytes(string.Format("msg${0}${1}", form, msg)));
            }
            catch (Exception e)
            {
                Log(e.Message);
            }
        }

        /// <summary>
        /// 定时删除已丢失的客户端
        /// </summary>
        private void TimeToClear()
        { 
            var clist=clients.Keys.ToArray();
            for (int i = 0; i < clist.Length; i++)
            {
                var item=clients[clist[i]];
                if (!item.Connected)
                {
                    dbs.LoginOut(clist[i]);
                    clients.Remove(clist[i]);
                }
            }
        }

        /// <summary>
        /// 停止监控端口
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnstop_Click(object sender, RoutedEventArgs e)
        {
            isListener = false;
            foreach (var item in clients.Values.ToArray())
            {
                try
                {
                    item.Close();
                    item.Dispose();
                }
                catch (Exception)
                {
                }
            }
            clients.Clear();
            if (listener != null)
            {
                listener.Stop();
            }
            dbs.RemoveAll();
            Log("已经停止监听！");
        }
    }
}
